#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <pthread.h>
#include <sys/types.h> /* See NOTES */
#include <sys/socket.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <unistd.h>

#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>

// 服务器的ip和port(本机)
#define SERVER_IP "192.168.2.48"
#define SERVER_PORT 62000
#define BUFFER_SIZE 1024

#define TRANS   "1"
#define DISPL   "2"
#define END     "3"
#define SIGN    "4"
#define LOOP    "5"

void send_file(int socket_fd, char *file_name)
{
    int ret = -1;
    
    //第一步：发送文件名
    ret = send(socket_fd, file_name, strlen(file_name), 0);
    if(ret < 0)
    {
        perror("file_name send failed");
        exit(1);
    }

    //第二步：发送文件大小
    int fd_file = open(file_name, O_RDWR);
    if(fd_file < 0)
    {
        perror("file open failed");
        exit(1);
    }

    int file_size = lseek(fd_file, 0, SEEK_END);
    lseek(fd_file, 0, SEEK_SET);
    ret = send(socket_fd, &file_size, sizeof(file_size), 0);
    if(ret < 0)
    {
        perror("filesize send failed");
        exit(1);
    }

    //第三步：发送文件内容
    int read_ret = 0;
    int total_size = 0;
    char buf[1024];
    while(1)
    {
        memset(buf, 0, sizeof(buf));
        read_ret = read(fd_file, buf, sizeof(buf));
        if(read_ret < 0)
        {
            perror("read failed");
            exit(1);
        }
        else if(read_ret > 0)
        {
            ret = send(socket_fd, buf, read_ret, 0);
            if(ret < 0)
            {
                perror("send failed");
                exit(1);
            }
            printf("send success ret: %d\n", ret);
        }
        else
        {
            printf("\n%s 已经传输完成\n", file_name);
            break;
        }
    }
}

void* send_client_info(void *arg)
{
    //设置自己分离属性
    pthread_detach(pthread_self());

    int ret = -1;
    int socket_fd = *(int *)arg;
    char buf[1024];

    while(1)
    {
        printf("============================\n");
        printf("请选择您的操作：\n");
        printf("1--->传输文件\n");
        printf("2--->播放广告\n");
        printf("============================\n");

        memset(buf, 0, sizeof(buf));
        scanf("%s", buf);
        // fgets(buf,sizeof(buf),stdin); //这个字符串可以带空格
        //给服务器发送数据(send/write)
        ret = send(socket_fd,buf,strlen(buf)-1,0); //-1是为了去掉回车符
        if(ret < 0)
        {
            printf("send fail\n");
            return NULL;
        }
        else
        {
            //传输文件
            if(strcmp(TRANS, buf) == 0)
            {    
                printf("准备传输文件...\n");

                int send_status[4] = {0, 0, 0, 0};
                int select = 0;
                int status = 1;
                while(status)
                {
                    printf("============================\n");
                    printf("请输入您要传输的文件名称：\n");
                    printf("0--->返回上一级\n");
                    printf("1--->凯迪拉克\n");
                    printf("2--->奥迪Q7\n");
                    printf("3--->迈腾\n");
                    printf("============================\n");

                    scanf("%d", &select);
                    while(getchar() != '\n');
                    switch(select)
                    {
                        case 0:
                            send(socket_fd, END, strlen(END), 0);
                            status = 0;
                            break;
                        case 1:
                            if(send_status[0] == 0)
                            {
                                send(socket_fd, TRANS, strlen(TRANS), 0);
                                send_file(socket_fd, "3-1.jpg");
                                send_status[0] = 1;
                            }
                            printf("该文件已传输\n");
                            break;
                        case 2:
                            if(send_status[1] == 0)
                            {
                                send(socket_fd, TRANS, strlen(TRANS), 0);
                                send_file(socket_fd, "3-2.jpg");
                                send_status[1] = 1;
                            }
                            printf("该文件已传输\n");
                            break;
                        case 3:
                            if(send_status[2] == 0)
                            {
                                send(socket_fd, TRANS, strlen(TRANS), 0);
                                send_file(socket_fd, "3-3.jpg");
                                send_status[2] = 1;
                            }
                            printf("该文件已传输\n");
                            break;
                        default:
                            printf("输入有误！请重新输入！\n");
                            break;
                    }
                }
            }

            //播放广告
            if(strcmp(DISPL, buf) == 0)
            {
                printf("准备播放广告...\n");

                int select = 0;
                int status = 1;
                //首先发送一个播放广告的指令
                send(socket_fd, DISPL, strlen(DISPL), 0);

                while(status)
                {
                    printf("============================\n");
                    printf("请输入您要播放的方式：\n");
                    printf("0--->返回上一级\n");
                    printf("1--->单独播放第一张\n");        //001
                    printf("2--->单独播放第二张\n");        //010
                    printf("3--->循环播放第一、二张\n");    //011
                    printf("4--->单独播放第三张\n");        //100
                    printf("5--->循环播放第一、三张\n");    //101
                    printf("6--->循环播放第二、三张\n");    //110
                    printf("7--->循环播放三张\n");          //111
                    printf("============================\n");

                    scanf("%d", &select);
                    while(getchar() != '\n');
                    switch(select)
                    {
                        case 0:
                            send(socket_fd, "000", strlen("000"), 0);
                            status = 0;
                            break;
                        case 1:
                            send(socket_fd, "001", strlen("001"), 0);
                            break;
                        case 2:
                            send(socket_fd, "010", strlen("010"), 0);
                            break;
                        case 3:
                            send(socket_fd, "011", strlen("011"), 0);
                            break;
                        case 4:
                            send(socket_fd, "100", strlen("100"), 0);
                            break;
                        case 5:
                            send(socket_fd, "101", strlen("101"), 0);
                            break;
                        case 6:
                            send(socket_fd, "110", strlen("110"), 0);
                            break;
                        case 7:
                            send(socket_fd, "111", strlen("111"), 0);
                            break;
                        default:
                            printf("输入有误！请重新输入！\n");
                            break;
                    }
                }
            }
        }
        printf("send success ret:%d\n", ret);
    }
}

int main(int argc, char **argv)
{
    int ret = 0;

    // 创建套接字(socket)
    // ipv4地址族 tcp协议
    int socket_fd = socket(AF_INET, SOCK_STREAM, 0);
    if (socket_fd < 0)
    {
        printf("socket fail\n");
        return -1;
    }

    // 所以设置端口号可以复用,这两条语句放在 绑定bind 之前
    int optval = 1;
    setsockopt(socket_fd, SOL_SOCKET, SO_REUSEADDR, &optval, sizeof(optval));

    // 绑定本机IP和port(bind)
    struct sockaddr_in server_addr;                     // 新的结构体
    server_addr.sin_family = AF_INET;                   // 地址族
    server_addr.sin_port = htons(SERVER_PORT);          // 将本机端口转换为网络端口(将小段字节序转换为大端字节序)
    server_addr.sin_addr.s_addr = inet_addr(SERVER_IP); // 将本机ip转换为网络ip
    ret = bind(socket_fd, (struct sockaddr *)&server_addr, sizeof(struct sockaddr_in));
    if (ret < 0)
    {
        printf("bind fail\n");
        return -1;
    }
    printf("绑定本机成功[%s][%d][%d]\n", SERVER_IP, SERVER_PORT,socket_fd);

    // 监听(listen)
    ret = listen(socket_fd, 20);
    if (ret < 0)
    {
        printf("listen fail\n");
        return -1;
    }

    // 连接客户端(accept)
    int socket_client = -1; // 用来存储客户端的套接字
    struct sockaddr_in client_addr;
    int addr_len = sizeof(struct sockaddr_in);
    socket_client = accept(socket_fd,(struct sockaddr *)&client_addr,(socklen_t * )&addr_len); //复杂的写法：接受数据同时接受客户端的地址
    // socket_client = accept(socket_fd, NULL, NULL); // 简单的写法：只接受数据 不需要知道谁发的
    if (socket_client < 0)
    {
        printf("accept fail\n");
        return -1;
    }
    //解析客户端的ip和port(需要将网络字节序转换为本机字节序)
    int port = ntohs(client_addr.sin_port); //将网络端口转换为本机端口
    // char *ip = inet_ntoa(client_addr.sin_addr.s_addr); //error
    char *ip = inet_ntoa(client_addr.sin_addr); //将网络ip转换为本机ip
    printf("新的客户端上线[%s][%d][%d]\n",ip,port,socket_client); //可以知道谁上线了

    //创建一个子线程用来发送客户端的数据
    pthread_t tid;
    ret = pthread_create(&tid,NULL,send_client_info,(void *)&socket_client);
    if(ret != 0)
    {
        printf("pthread_create fail\n");
        return -1;
    }    
    pthread_join(tid, NULL);

    // 接收客户端发送的数据(recv/read)
    char buf[1024] = {0};
    while(1)
    {
        memset(buf,0,sizeof(buf));

        ret = recv(socket_client, buf, sizeof(buf), 0);
        if (ret < 0)
        {
            printf("recv fail\n");
            return -1;
        }
        if(ret == 0)
        {
            printf("客户端掉线[%s][%d]\n",ip,port);
            break;
        }

        printf("[%s][%d]recv success buf:%s ret:%d\n",ip,port, buf, ret);
    }   


    // 关闭套接字(close)
    close(socket_fd);
    close(socket_client);

    return 0;
}